// Include files.
#include <map>
#include "ChainState.hpp"

// Use namespaces.
using namespace std;

/**
 *  Constructor for ChainState.
 */
ChainState::ChainState() :
	m_stateSuccess(),
	m_stateError(),
	m_stateInital(NULL),
	m_stateLastAppended(NULL)
{
}

/**
 *  Appends a State onto the chain of States to be run.
 *  
 *  @param state The State to be appended.
 */
void ChainState::AppendState(State &state)
{
	// If this is the first state, it will append to this state.
	if (m_stateLastAppended != NULL)
	{
		m_stateLastAppended->AddTransition
		(
			StateDoneCode::GetSuccessCode(),
			state
		);
	}
	else
	{
		m_stateInital = &state;
	}
	
	// Check if there is already a error catching transition.
	if (state.GetTransitions().count(StateDoneCode::GetGenericErrorCode() == 0))
	{
		state.AddTransition
		(
			StateDoneCode::GetGenericErrorCode(),
			m_stateError
		);
	}
	
	m_stateLastAppended = &state;
}

void ChainState::InitializeImpl()
{
	const map<StateDoneCode, State*> &transitions = GetTransitions();
	
	// Add a transition from the last appended state to the success state.
	m_stateLastAppended->AddTransition
	(
		StateDoneCode::GetSuccessCode(),
		m_stateSuccess
	);
	
	if (transitions.count(StateDoneCode::GetSuccessCode()) > 0)
	{
		m_stateSuccess.AddTransition
		(
			*(*transitions.find(StateDoneCode::GetSuccessCode())).second
		);
	}
	
	if (transitions.count(StateDoneCode::GetGenericErrorCode()) > 0)
	{
		/* Instant state always use success.
		 * So we need to have the error transition
		 * transition from a success done code.
		 */
		m_stateError.AddTransition
		(
			*(*transitions.find(StateDoneCode::GetGenericErrorCode())).second
		);
	}
	
	AddTransition
	(
		StateDoneCode::GetSuccessCode(), 
		*m_stateInital
	);
	
	SetDoneCode(StateDoneCode::GetSuccessCode());
}
